/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.common.base.service.rpc;

import com.je.common.base.DynaBean;
import com.je.common.base.constants.table.ColumnType;
import com.je.common.base.entity.func.FuncRelationField;
import com.je.core.entity.extjs.JSONTreeNode;
import java.util.List;
import java.util.Map;

/**
 * @program: jecloud-common
 * @author: LIULJ
 * @create: 2021-02-25 15:55
 * @description:
 */
public interface BeanService {

    /** 特殊属性：表编码 */
    String KEY_TABLE_CODE = "$TABLE_CODE$";

    /** 特殊属性：结果集 */
    String KEY_ROWSET = "$ROWSET$";

    /** 特殊属性：当前页面记录数 */
    String KEY_PAGE_COUNT = "$P_COUNT$";

    /** 特殊属性：总记录数 */
    String KEY_ALL_COUNT = "$A_COUNT$";

    /** 特殊属性：查询结果的列表 */
    String KEY_COLUMNS = "$A_COLUMENS$";

    /** 特殊属性：本条数据的所在行数 */
    String KEY_ROW_NUM = "$ROW_NUM$";

    /** 特殊属性：SQL语句 */
    String KEY_SQL = "$SQL$";

    /** 特殊属性：select字段列 */
    String KEY_SELECT = "$SELECT$";

    /** 特殊属性：Where条件 */
    String KEY_WHERE = "$WHERE$";

    /** 特殊属性：group by */
    String KEY_GROUP = "$GROUP$";

    /** 特殊属性: Order By */
    String KEY_ORDER = "$ORDER$";

    /** 特殊属性：主键字符串 */
    String KEY_PK_CODE = "$PK_CODE$";

    /** 特殊属性：查询字段集合 */
    String KEY_QUERY_FIELDS = "$QUERY_FIELDS$";

    /** 特殊属性：表的所有列*/
    String KEY_TABLE_COLUMNS = "$TABLECOLUMNS$";

    /** 特殊属性：表的所有键 */
    String KEY_TABLE_KEYS = "$TABLEKEYS$";
    /** 特殊属性：表的所有索引 */
    String KEY_TABLE_INDEXS = "$TABLEINDEXS$";

    /** 特殊属性：大文本内容 */
    String KEY_LONG_FIELD = "$LONG$";

    /** 特殊属性：操作用户名 */
    String KEY_USER = "$USER$";

    /** 特殊属性：request对象 */
    String KEY_REQUEST = "$REQUEST$";

    /** 特殊属性：response对象 */
    String KEY_RESPONSE = "$RESPONSE$";

    /** 特殊属性：唯一组重复字段 */
    String KEY_DUPCODE = "$DUPCODE$";

    /** 上传文档信息 */
    String KEY_DOC_INFO = "$DOC_INFO$";

    /** 参数属性：是否进行数据库匹配 */
    String PARAM_IS_DBMAP = "isDBMap";

    /** 表定义的参数：字段列表 */
    String DEF_ALL_FIELDS = "$ALL_FIELDS$";

    /** 表定义的参数：主键列表 */
    String DEF_PK_FIELDS = "PK_FIELDS";

    /** 表定义的参数：非主键列表 */
    String DEF_NPK_FIELDS = "NPK_FIELDS";

    /** 特殊属性：空字符串，在Where生成时使用自动替换为空 */
    String KEY_VALUE_NULL = "~$￥$~==~￥$￥~";

    /** 特殊属性：数字零，在Where生成时使用自动替换为数字零 */
    String KEY_VALUE_ZERO = "~￥$￥~==~$￥$~";

    /** 特殊属性：是否在流程中，当前数据Bean是否在流程处理中执行 */
    String KEY_IS_IN_WORKFLOW = "$IS_IN_WORKFLOW$";

    /**
     * 根据表编码得到表的描述性信息
     * @param tableCode
     * @return
     */
    DynaBean getResourceTable(String tableCode);

    /**
     * 根据表定义的编码得到对应的主键字段名称列表
     * @param dynaBean
     * @return
     */
    String getPKeyFieldNames(DynaBean dynaBean);

    /**
     * 根据表定义的编码得到对应的主键字段名称列表
     * @param tableCode
     * @return
     */
    String getPKeyFieldNamesByTableCode(String tableCode);

    /**
     * 获取当前表外键字段CODE
     * @param tableCode
     * @param parentTableCode
     * @param parentPkCode
     * @param relatedFields
     * @return
     */
    String getForeignKeyField(String tableCode,String parentTableCode,String parentPkCode,List<FuncRelationField> relatedFields);

    /**
     * 得到动态类的所有属性的名称
     * @param dynaBean
     * @return
     */
    String[] getNames(DynaBean dynaBean);

    /**
     * 得到动态类所有的属性名称,中间用","分开
     * @param table
     * @return
     */
    String getNames4Sql(DynaBean table);

    /**
     * 得到修改信息的sql语句段
     * @param resourceTable
     * @param values
     * @return
     */
    String getUpdateInfos4Sql(DynaBean resourceTable,Map<String,Object> values);

    /**
     * 得到动态类所有的属性名称,中间用","分开
     * @param dynaBean
     * @return
     */
    String getNames2DynaBean4Sql(DynaBean dynaBean);

    /**
     * 得到动态类的所有属性名称,格式化成 :name ,:age 的样子用于Sql
     * @param table
     * @return
     */
    String getValues4Sql(DynaBean table);

    /**
     * 根据ResourceTable得到DynaBean的结构
     * @param table
     * @return
     */
    DynaBean getDynaBeanByResourceTable(DynaBean table);

    /**
     * 得到动态类的所有值的内容
     * @param dynaBean
     * @return
     */
    Object[] getValues(DynaBean dynaBean);

    /**
     * 将更新字符串josn构建成list的dynaBean集合
     * @param updateStr
     * @param tableCode
     * @return
     */
    List<DynaBean> buildUpdateList(String updateStr,String tableCode);

    /**
     * 获取dynaBean的id数组  便于查询
     * @param beans
     * @param pkCode
     * @return
     */
    String[] getDynaBeanIdArray(List<DynaBean> beans,String pkCode);

    /**
     * 初始化资源表 结构
     * @param tableCode
     * @return
     */
    DynaBean initSysTable(String tableCode);

    /**
     * 拼接指定表的所有列 字段的字符串     SY_CREATEUSER,SY_CREATETIME,SY_STATUS
     * @param resourceTable
     * @param excludes
     * @return
     */
    String getFieldNames(DynaBean resourceTable,String[] excludes);

    /**
     * 获取系统级别的查询字段(含主键)
     * 当需要查询局部字段的时候，使用此方法获取到所有系统级别，然后再根据资源表把需查询业务字段拼接
     * 如： 局部查询TEST_FIELD1,TEST_FIELD2和所有系统字段   "TEST_FIELD1,TEST_FIELD2,"+BeanUtils.getInstance().getSysQueryFields(表名)
     * @param tableCode
     * @return
     */
    String getSysQueryFields(String tableCode);

    /**
     * 获取业务级别的查询字段(不含主键)
     * 当需要局部查询业务字段数据时，使用此方法可以得到所有业务字段
     * 如：局部查询业务字段和主键    "主键,"+BeanUtils.getInstance().getSysQueryFields(表名)
     * @param tableCode 表名
     * @return 查询字段按逗号隔开
     */
    String getProQueryFields(String tableCode);

    /**
     * 获取查询字段
     * 当 需要查询所有字段想指定排除一些存储量大的字段，使用此方法可以完成操作
     * @param tableCode 表名
     * @param excludes 排除字段
     * @return 查询字段按逗号隔开
     */
    String getQueryFields(String tableCode,String[] excludes);

    /**
     * 获取不包含大文本的所有字段
     * 当需要查询数据用于操作时，一些大文本字段不会被操作和修改，则可以调用方法获取到查询字段(不包含大文本字段)
     * 大文本字段：MySql的text SQLServer的text Oracle的clob(clob字段尽量别查询，因为查询要构建值的过程需用到文件流，会暂用java的内存很大)
     * @param tableCode 表名
     * @return 查询字段按逗号隔开
     */
    String getNoClobQueryFields(String tableCode);

    /**
     * 得到树形模版对象
     * @param tableCode
     * @return
     */
    JSONTreeNode getTreeTemplate(String tableCode);

    /**
     * 构建dyanBean的树形模版类
     * 排除bean的大文本字段
     * @param columns
     * @return
     */
    JSONTreeNode buildJSONTreeNodeTemplate(List<DynaBean> columns);

    /**
     * 获取字符串过长的字段code
     * @return
     */
    default String getStringLong(DynaBean dynaBean){
        DynaBean resourceTable=getResourceTable(dynaBean.getStr(KEY_TABLE_CODE));
        List<DynaBean> columns=(List<DynaBean>) resourceTable.get(KEY_TABLE_COLUMNS);
        String errors="";
        for(DynaBean column:columns){
            String type=column.getStr("TABLECOLUMN_TYPE");
            String code=column.getStr("TABLECOLUMN_CODE");
            //排除字段
            if(ColumnType.NUMBER.equals(type) || ColumnType.CLOB.equals(type)|| ColumnType.BIGCLOB.equals(type) || ColumnType.FLOAT.equals(type) || ColumnType.CUSTOM.equals(type)){
                continue;
            }
            Integer length=255;
            if(ColumnType.ID.equals(type) || ColumnType.FOREIGNKEY.equals(type) || ColumnType.DATETIME.equals(type)){
                length=50;
            }else if(ColumnType.VARCHAR100.equals(type)){
                length=100;
            }else if(ColumnType.VARCHAR50.equals(type)){
                length=50;
            }else if(ColumnType.VARCHAR30.equals(type)){
                length=30;
            }else if(ColumnType.VARCHAR767.equals(type)){
                length=767;
            }else if(ColumnType.VARCHAR1000.equals(type)){
                length=1000;
            }else if(ColumnType.VARCHAR2000.equals(type)){
                length=2000;
            }else if(ColumnType.VARCHAR4000.equals(type)){
                length=4000;
            }else if(ColumnType.VARCHAR.equals(type)){
                length=Integer.parseInt(column.getStr("TABLECOLUMN_LENGTH","0"));
            }else if(ColumnType.VARCHAR4000.equals(type)){
                length=4000;
            }else if(ColumnType.YESORNO.equals(type)){
                length=4;
            }
            if(dynaBean.containsKey(code)){
                String value=dynaBean.getStr(code);
                if(value.length()>length){
                    errors=column.getStr("TABLECOLUMN_NAME")+"【"+column.getStr("TABLECOLUMN_CODE")+"】字段过长，请修改字段类型!";
                    break;
                }
            }
        }
        return errors;
    }

}
